package android.tusnotas.connector.webservice;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

import android.content.SharedPreferences;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.provider.Settings;
import android.tusnotas.connector.TusNotasCaller;
import android.tusnotas.connector.TusNotasHttpClient;
import android.tusnotas.core.GradeAnalyserStatuses;
import android.tusnotas.exception.RemoteReadingException;
import android.tusnotas.model.TusNotasModel;
import android.tusnotas.util.Devel;
import android.tusnotas.util.Properties;
import android.tusnotas.util.PropertyLoader;
import android.tusnotas.util.StringConverter;
import android.util.Log;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

public class WebServiceCaller extends TusNotasCaller {
	
	private static final Integer GET_GRADES = 1;
	private static final Integer GET_MORE_INFO_COURSE = 2;
	private static final Integer GET_MORE_INFO_GROUP = 3;
	private static final Integer GET_MORE_INFO_VERSION = 4;
	private static final Integer GET_NOTIFICACIONES_PUSH = 5;
	private static final Integer SUSCRIBIR_PUSH = 6;
	private static final Integer DESSUSCRIBIR_PUSH = 7;
	private static final Integer ACK_PUSH = 8;
	private static final Integer SEND_MESSAGE = 9;
	
	private DefaultHttpClient client;
	private Integer function = GET_GRADES;
	private String aulaID;
	private String clientVersion;
	private String appId;
	private String groupId;
	private String message;
	
	private Context context = null;
    private String androidId;

    public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	private DefaultHttpClient prepareHttpClient(){

		TusNotasHttpClient httpClient = TusNotasHttpClient.getWebCampusHttpClient();
        final HttpParams httpParams = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, 5000);
        return httpClient;
	}
	
	public void setForGrades(){
		function = GET_GRADES;
	}
	
	public void SetForMoreInfoCouse(String aulaID){
		function = GET_MORE_INFO_COURSE;
		this.aulaID = aulaID; 
	}

	public void setInfoGroup(String aulaID){
		function = GET_MORE_INFO_GROUP;
		this.aulaID = aulaID;
	}
	
	public void setInfoVersion(String appId, String clientVersion){
		function = GET_MORE_INFO_VERSION;
		this.appId = appId;
		this.clientVersion = clientVersion;
	}
	
	public void setPushNotification(String appId, String androidId){
		function = GET_NOTIFICACIONES_PUSH;
		this.appId = appId;
        this.setAndroidId(androidId);
	}
	
	public void setPushSubscription(String appId, String androidId){
		function = SUSCRIBIR_PUSH;
		this.appId = appId;
        this.setAndroidId(androidId);
	}
	
	public void setPushUnsubscription(String appId, String androidId){
		function = DESSUSCRIBIR_PUSH;
		this.appId = appId;
        this.setAndroidId(androidId);
	}
	
	//AckNotificacionesPush/{hash}/{androidId}/{AppId}?format={format}

	public void setAckPush(String appId, String androidId){
		function = ACK_PUSH;
        this.appId = appId;
		this.setAndroidId(androidId);
	}
	
	public void setSendMessage(String groupId, String message){
		function = SEND_MESSAGE;
		this.groupId=groupId;
		this.message=message;
	}
	
	//setea el hash en el atributo cookie
	private void login() throws RemoteReadingException{
		
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		try {
			client = prepareHttpClient();
			
			String username = PropertyLoader.USERNAME;
		    String password = PropertyLoader.PASSWORD;

            HttpGet get = new HttpGet(WebServiceURLs.LOGIN + username + "/" + password);
			HttpResponse httpResponse = client.execute(get);
			Integer statusCode = httpResponse.getStatusLine().getStatusCode();
			
			switch (statusCode) {
			case -1:
				connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
				break;
			case 0:
				connectionStatus = GradeAnalyserStatuses.WRONG_USER_OR_PASS;
				break;
			default:
				cookie = StringConverter.slurp(httpResponse.getEntity().getContent());
				if (Devel.callerDevel || Devel.fullDevel){
					Log.w(this.getClass().getName(), "Log in to Webservice OK.");
				}
				cookie = cookie.replace("\"", "");
				// save hash
				if (this.context!=null && !cookie.contains("html")){
					TusNotasModel.getTusNotasModel(context).updateProperty(Properties.HASH, cookie);
					Log.e(getClass().getName(),"Saved hash: "+cookie);

				}else {
					Log.e(getClass().getName(),"Could not save hash: no context");
				}
				
				Log.e("COOKIE:",cookie);
				return;
			}
		}
		catch( UnsupportedEncodingException ueException ) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		catch (IOException ioException) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
        }
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
        }
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Log in to Webservice NOT OK.");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	private String getMoreInfoCouse(String aulaID) throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.NEWS_FOLDERS_FILES + cookie + "" +
					"" +
					"/" + aulaID;
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {

//				Header[] locationHeaders = httpResponse.getHeaders("Location");
//				if (locationHeaders != null && locationHeaders.length > 0){
//					if (WebServiceURLs.LOGIN_URI.equals(locationHeaders[0].getValue().trim())){
//						login();
//						client = prepareHttpClient();
//						get = new HttpGet(WebServiceURLs.NOTAS + cookie);
//						httpResponse = client.execute(get);
//					}
//				}
//				if (Devel.callerDevel || Devel.fullDevel){
//					Log.w(this.getClass().getName(), "Getting Grades from Webservice Home OK");
//				}
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}

		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	private String getInfoVersion(String appId, String clientVersion) throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			//String ws = WebServiceURLs.INFO_VERSION + appId + "/" + clientVersion;
			String ws = WebServiceURLs.INFO_VERSION + clientVersion + "/" + appId;

			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}

	private String suscribirPush(String appId)throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.PUSH_SUBSCRIBE + cookie + "/1/"+
			getAndroidId()
			+ "/" + appId + "?format=xml";
			Log.w("Push Subscription URL: ",ws);
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Subscribing push notifications Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}

	private String desSuscribirPush(String appId)throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.PUSH_UNSUBSCRIBE + cookie + "/"+
            getAndroidId()
            + "/" + appId + "?format=xml";
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Unsubscribing push notifications Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	private String getNotificacionesPush(String appId) throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.PUSH_NOTIFICATIONS + cookie + "/"+
            getAndroidId()
            + "/" + appId + "?format=xml";
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting push notifications from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	// AckNotificacionesPush/{hash}/{AndroidId}/{AppId}?format={format}
	private String ackPush(String appId, String androidId) throws RemoteReadingException {
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.ACK_PUSH + cookie + "/" + androidId+"/"+ appId + "?format=xml";
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	private String sendMessage() throws RemoteReadingException {
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String comment = commentToJSON(this.message);
			String ws = WebServiceURLs.GROUP_MESSAGES+cookie+"/"+groupId;
			
			StringEntity se = new StringEntity(comment);
			
			HttpPost post = new HttpPost(ws);
			
			post.setEntity(se);
			
			post.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
			post.setHeader("User-Agent", "CanDoIt");
			post.setHeader("Content-Type", "application/json");
			post.setHeader("Host", "www.webcampus.uade.edu.ar");
			//post.setHeader("Content-Length",""+se.getContentLength());

			HttpResponse httpResponse = client.execute(post);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
		
	private String commentToJSON(String comment) {
		comment = replace(comment, "\"", "\\\"");
		comment = replace(comment, "\n", "\\n");
		System.out.println("{\"Comment\":"+comment+"\"}");
		return "{\"Comment\":\""+comment+"\"}";
	}
	
	private String replace(String text, String from, String to){
		StringBuffer sb = new StringBuffer();
		int fromPos = text.indexOf(from);
		int startPos =0;
		int fromLength = from.length();
		while(fromPos!=-1){
			sb.append(text.substring(startPos,fromPos)).append(to);
			startPos = fromPos+fromLength;
			fromPos = text.indexOf(from, startPos);
		}
		sb.append(text.substring(startPos,text.length()));
		return sb.toString();
	}
	
	private String getInfoGroup(String aulaID) throws RemoteReadingException{
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");

		try {
			client = prepareHttpClient();
			String ws = WebServiceURLs.INFO_GROUP + cookie + "/" + aulaID;
			HttpUriRequest get = new HttpGet(ws);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);

			HttpResponse httpResponse = client.execute(get);

			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}

		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}

	private String getGrades() throws RemoteReadingException{
		
		Integer connectionStatus = GradeAnalyserStatuses.NO_FAILURE; 
		RemoteReadingException rwce = null;
		Log.w(this.getClass().getName(), "starting...");
		
		try {
			
			client = prepareHttpClient();
			HttpUriRequest get = new HttpGet(WebServiceURLs.NOTAS + cookie);
			get.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
            Log.d("GetGrades URL", WebServiceURLs.NOTAS + cookie);

            HttpResponse httpResponse = client.execute(get);
			
			if (httpResponse.getStatusLine().getStatusCode() != -1 ) {
				
				Header[] locationHeaders = httpResponse.getHeaders("Location");
				if (locationHeaders != null && locationHeaders.length > 0){
					if (WebServiceURLs.LOGIN_URI.equals(locationHeaders[0].getValue().trim())){
						login();
						client = prepareHttpClient();
						get = new HttpGet(WebServiceURLs.NOTAS + cookie);
						httpResponse = client.execute(get);
					}
				}
				if (Devel.callerDevel || Devel.fullDevel){
					Log.w(this.getClass().getName(), "Getting Grades from Webservice Home OK");
				}
				return StringConverter.slurp(httpResponse.getEntity().getContent());
			}
			return "";
		}
		
		catch (IOException ioe) {
			connectionStatus = GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT;
		}
		catch (Exception e) {
			connectionStatus = GradeAnalyserStatuses.WEIRD_FAILURE;
		}
		if (Devel.callerDevel || Devel.fullDevel){
			Log.w(this.getClass().getName(), "Getting Grades from Webservice NOT OK");
		}
		rwce = new RemoteReadingException();
		rwce.setErrorCode(connectionStatus);
		throw rwce;
	}
	
	/* (non-Javadoc)
	 * @see android.tusnotas.connector.Caller#execute()
	 */
	@Override
	public String execute() throws RemoteReadingException{
		if (cookie == null || "".equals(cookie.trim())){
			login();
		}
		
		String XML=null;
		
		if (getFunction() == GET_GRADES){
			XML = getGrades();
		}else if(getFunction() == GET_MORE_INFO_COURSE){
			XML = getMoreInfoCouse(this.aulaID);
		}else if(getFunction() == GET_MORE_INFO_GROUP){
			XML = getInfoGroup(this.aulaID);
		}else if(getFunction() == GET_MORE_INFO_VERSION){
			XML = getInfoVersion(this.appId, this.clientVersion);
		} else if (getFunction() == GET_NOTIFICACIONES_PUSH){
			XML = getNotificacionesPush(this.appId);
		} else if (getFunction() == SUSCRIBIR_PUSH){
			XML = suscribirPush(this.appId);
		} else if (getFunction() == DESSUSCRIBIR_PUSH){
			XML = desSuscribirPush(this.appId);
		} else if (getFunction() == ACK_PUSH){
			XML = ackPush(this.appId, this.getAndroidId());
		} else if (getFunction() == SEND_MESSAGE){
			XML = sendMessage();
		}

		if (XML != null && !XML.equals("")){
			return XML;
		}
		
		RemoteReadingException rwce = new RemoteReadingException();
		rwce.setErrorCode(GradeAnalyserStatuses.WEIRD_FAILURE);
		throw rwce;
	}

	public Integer getFunction() {
		return function;
	}

    public String getAndroidId() {
        return androidId;
    }

    public void setAndroidId(String androidId) {
        if(this.androidId == null)
            this.androidId = androidId;
    }
}
